(use-modules
 ;; SRFI 64 for unit testing facilities
 (srfi srfi-64)
 ;; SRFI 8 for `receive` form
 (srfi srfi-8)
 ;; utils - the code to be tested
 (decision-tree)
 ;; Utilities for testing
 (utils test)
 ;; Dependencies for testing the code to be tested
 (dataset)
 (metrics)
 (pruning)
 (prediction)
 (data-point)
 (tree))


(define TEST-DATA
  (list #(2.771244718 1.784783929 0)
        #(1.728571309 1.169761413 0)
        #(3.678319846 2.81281357 0)
        #(3.961043357 2.61995032 0)
        #(2.999208922 2.209014212 0)
        #(7.497545867 3.162953546 1)
        #(9.00220326 3.339047188 1)
        #(7.444542326 0.476683375 1)
        #(10.12493903 3.234550982 1)
        #(6.642287351 3.319983761 1)))


(define PRECISION (expt 10 -9))


(test-begin "prediction-test")


(test-group
 "predict-at-leaf-node"
 (test-equal
     1
   (predict-at-leaf-node (make-leaf-node (list #(1.0 2.0 0)
                                               #(3.0 4.0 0)
                                               #(5.0 6.0 1)
                                               #(7.0 8.0 1)
                                               #(9.0 0.0 1)))
                         2))

 (test-equal
     0
   (predict-at-leaf-node (make-leaf-node (list #(1.0 2.0 0)
                                               #(3.0 4.0 0)
                                               #(5.0 6.0 0)
                                               #(7.0 8.0 1)
                                               #(9.0 0.0 1)))
                         2)))


(test-group
 "dataset-majority-prediction"
 (test-equal
     1
   (dataset-majority-prediction (list #(2.3 1.1 0)
                                      #(2.0 1.1 0)
                                      #(2.3 1.0 1)
                                      #(2.0 1.0 1)
                                      #(2.3 1.0 1)
                                      #(2.0 1.0 1)
                                      #(2.4 1.0 1))
                                2))

 (test-equal
     0
   (dataset-majority-prediction (list #(2.3 1.1 0)
                                      #(2.0 1.1 0)
                                      #(2.3 1.0 0)
                                      #(2.0 1.0 0)
                                      #(2.3 1.0 1)
                                      #(2.0 1.0 1)
                                      #(2.4 1.0 1))
                                2))

 (test-equal
     0
   (dataset-majority-prediction (list #(2.3 1.1 0)
                                      #(2.0 1.1 0)
                                      #(2.3 1.0 0)
                                      #(2.0 1.0 0)
                                      #(2.3 1.0 1)
                                      #(2.0 1.0 1)
                                      #(2.4 1.0 1)
                                      #(2.4 1.0 1))
                                2)))


#;(test-group
 "node-majority-prediction"
 (test-equal
     1
   (node-majority-prediction
    (make-node (list #(2.3 1.1 0)
                     #(2.0 1.1 0)
                     #(2.3 1.0 1)
                     #(2.0 1.0 1)
                     #(2.3 1.0 1)
                     #(2.0 1.0 1)
                     #(2.4 1.0 1))
               1
               1.1
               (list #(2.3 1.0 1)
                     #(2.0 1.0 1)
                     #(2.3 1.0 1)
                     #(2.0 1.0 1)
                     #(2.4 1.0 1))
               (list #(2.3 1.1 0)
                     #(2.0 1.1 0)))
    2))

 (test-equal
     0
   (node-majority-prediction
    (make-node (list #(2.3 1.1 1)
                     #(2.0 1.1 1)
                     #(2.3 1.0 0)
                     #(2.0 1.0 0)
                     #(2.3 1.0 0)
                     #(2.0 1.0 0)
                     #(2.4 1.0 0))
               1
               1.1
               (list #(2.3 1.0 0)
                     #(2.0 1.0 0)
                     #(2.3 1.0 0)
                     #(2.0 1.0 0)
                     #(2.4 1.0 0))
               (list #(2.3 1.1 1)
                     #(2.0 1.1 1)))
    2)))


(test-group
 "predict"
 (let ([tree (make-node (list #(1.0 1.0 0)
                              #(1.2 1.0 0)
                              #(1.1 1.0 0)
                              #(1.4 1.0 0)
                              #(1.2 1.0 0)
                              #(1.2 1.0 0) ;
                              #(2.3 1.1 0)
                              #(2.0 1.1 0) ;;
                              #(2.3 1.0 1)
                              #(2.0 1.0 1)
                              #(2.3 1.0 1)
                              #(2.0 1.0 1)
                              #(2.4 1.0 1))
                        0  ;; split index
                        2.0  ;; split value
                        (make-leaf-node (list #(1.0 1.0 0)
                                              #(1.2 1.0 0)
                                              #(1.1 1.0 0)
                                              #(1.4 1.0 0)
                                              #(1.2 1.0 0)
                                              #(1.2 1.0 0)))
                        (make-node (list #(2.3 1.1 0)
                                         #(2.0 1.1 0)
                                         #(2.3 1.0 1)
                                         #(2.0 1.0 1)
                                         #(2.3 1.0 1)
                                         #(2.0 1.0 1)
                                         #(2.4 1.0 1))
                                   1
                                   1.1
                                   (make-leaf-node (list #(2.3 1.0 1)
                                                         #(2.0 1.0 1)
                                                         #(2.3 1.0 1)
                                                         #(2.0 1.0 1)
                                                         #(2.4 1.0 1)))
                                   (make-leaf-node (list #(2.3 1.1 0)
                                                         #(2.0 1.1 0)))))])
   (test-equal (predict tree #(2.3 1.1 0) 2) 0)
   (test-equal (predict tree #(2.3 1.0 0) 2) 1)))


(test-group
 "predict-dataset"
 (let ([tree (make-node (list #(1.0 1.0 0)
                              #(1.2 1.0 0)
                              #(1.1 1.0 0)
                              #(1.4 1.0 0)
                              #(1.2 1.0 0)
                              #(1.2 1.0 0) ;
                              #(2.3 1.1 0)
                              #(2.0 1.1 0) ;;
                              #(2.3 1.0 1)
                              #(2.0 1.0 1)
                              #(2.3 1.0 1)
                              #(2.0 1.0 1)
                              #(2.4 1.0 1))
                        0
                        2.0
                        (make-leaf-node (list #(1.0 1.0 0)
                                              #(1.2 1.0 0)
                                              #(1.1 1.0 0)
                                              #(1.4 1.0 0)
                                              #(1.2 1.0 0)
                                              #(1.2 1.0 0)))
                        (make-node (list #(2.3 1.1 0)
                                         #(2.0 1.1 0)
                                         #(2.3 1.0 1)
                                         #(2.0 1.0 1)
                                         #(2.3 1.0 1)
                                         #(2.0 1.0 1)
                                         #(2.4 1.0 1))
                                   1
                                   1.1
                                   (make-leaf-node (list #(2.3 1.0 1)
                                                         #(2.0 1.0 1)
                                                         #(2.3 1.0 1)
                                                         #(2.0 1.0 1)
                                                         #(2.4 1.0 1)))
                                   (make-leaf-node (list #(2.3 1.1 0)
                                                         #(2.0 1.1 0)))))])
   (test-equal
       (list 0 1)
     (predict-dataset tree (list #(2.3 1.1 0)
                                 #(2.3 1.0 0))
                      2))))


(test-group
 "predict-dataset"
 (let ([tree (make-node (list #(2.3 1.1 0)
                              #(2.0 1.1 0)
                              #(2.3 1.0 1)
                              #(2.0 1.0 1)
                              #(2.3 1.0 1)
                              #(2.0 1.0 1)
                              #(2.4 1.0 1))
                        1
                        1.1
                        (make-leaf-node (list #(2.3 1.0 1)
                                              #(2.0 1.0 1)
                                              #(2.3 1.0 1)
                                              #(2.0 1.0 1)
                                              #(2.4 1.0 1)))
                        (make-leaf-node (list #(2.3 1.1 0)
                                              #(2.0 1.1 0))))])
   (test-equal "prediction for a tiny dataset"
     (list 0 1 0 1)
     (predict-dataset tree
                      (list #(2.4 1.2)
                            #(1.9 0.9)
                            #(3.0 3.0)
                            #(0.0 0.5))
                      2))))


(test-end "prediction-test")
